package com.mqtt.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 协议处理器
 */
@Slf4j
@Component
public class ProtocolHandler {
    
    @Autowired
    private MessageChannel mqttOutboundChannel;
    
    private final Map<String, ProtocolParser> protocolParsers = new HashMap<>();
    
    public ProtocolHandler() {
        // 注册协议解析器
        registerProtocolParsers();
    }
    
    /**
     * 注册协议解析器
     */
    private void registerProtocolParsers() {
        // JSON协议
        protocolParsers.put("json", new JsonProtocolParser());
        // 自定义二进制协议
        protocolParsers.put("binary", new BinaryProtocolParser());
        // Modbus协议
        protocolParsers.put("modbus", new ModbusProtocolParser());
    }
    
    /**
     * 解析消息
     */
    public Map<String, Object> parseMessage(String protocolType, byte[] data) {
        ProtocolParser parser = protocolParsers.get(protocolType.toLowerCase());
        if (parser == null) {
            log.warn("Unsupported protocol type: {}", protocolType);
            parser = protocolParsers.get("json"); // 默认使用JSON
        }
        
        try {
            return parser.parse(data);
        } catch (Exception e) {
            log.error("Error parsing message with protocol: {}", protocolType, e);
            return new HashMap<>();
        }
    }
    
    /**
     * 发送消息到MQTT
     */
    public void sendMessage(String topic, String payload) {
        sendMessage(topic, payload, 1, false);
    }
    
    /**
     * 发送消息到MQTT（指定QoS和retained）
     */
    public void sendMessage(String topic, String payload, int qos, boolean retained) {
        try {
            Message<String> message = MessageBuilder
                    .withPayload(payload)
                    .setHeader(MqttHeaders.TOPIC, topic)
                    .setHeader(MqttHeaders.QOS, qos)
                    .setHeader(MqttHeaders.RETAINED, retained)
                    .build();
            
            mqttOutboundChannel.send(message);
            log.debug("Sent MQTT message to topic: {}", topic);
            
        } catch (Exception e) {
            log.error("Error sending MQTT message to topic: {}", topic, e);
        }
    }
    
    /**
     * 发送二进制消息
     */
    public void sendBinaryMessage(String topic, byte[] data) {
        sendBinaryMessage(topic, data, 1, false);
    }
    
    /**
     * 发送二进制消息（指定QoS和retained）
     */
    public void sendBinaryMessage(String topic, byte[] data, int qos, boolean retained) {
        try {
            Message<byte[]> message = MessageBuilder
                    .withPayload(data)
                    .setHeader(MqttHeaders.TOPIC, topic)
                    .setHeader(MqttHeaders.QOS, qos)
                    .setHeader(MqttHeaders.RETAINED, retained)
                    .build();
            
            mqttOutboundChannel.send(message);
            log.debug("Sent binary MQTT message to topic: {}", topic);
            
        } catch (Exception e) {
            log.error("Error sending binary MQTT message to topic: {}", topic, e);
        }
    }
    
    /**
     * 协议解析器接口
     */
    interface ProtocolParser {
        Map<String, Object> parse(byte[] data) throws Exception;
    }
    
    /**
     * JSON协议解析器
     */
    static class JsonProtocolParser implements ProtocolParser {
        @Override
        public Map<String, Object> parse(byte[] data) throws Exception {
            String json = new String(data, StandardCharsets.UTF_8);
            return com.alibaba.fastjson.JSON.parseObject(json, Map.class);
        }
    }
    
    /**
     * 二进制协议解析器
     */
    static class BinaryProtocolParser implements ProtocolParser {
        @Override
        public Map<String, Object> parse(byte[] data) throws Exception {
            Map<String, Object> result = new HashMap<>();
            
            // 实现二进制协议解析逻辑
            // 例如：前4字节为设备ID，接下来2字节为数据类型，后续为数据内容
            if (data.length < 6) {
                throw new IllegalArgumentException("Invalid binary data length");
            }
            
            // 解析示例
            int deviceId = ((data[0] & 0xFF) << 24) | 
                          ((data[1] & 0xFF) << 16) | 
                          ((data[2] & 0xFF) << 8) | 
                          (data[3] & 0xFF);
            
            int dataType = ((data[4] & 0xFF) << 8) | (data[5] & 0xFF);
            
            result.put("deviceId", deviceId);
            result.put("dataType", dataType);
            
            // 解析数据内容
            if (data.length > 6) {
                byte[] payload = new byte[data.length - 6];
                System.arraycopy(data, 6, payload, 0, payload.length);
                result.put("payload", payload);
            }
            
            return result;
        }
    }
    
    /**
     * Modbus协议解析器
     */
    static class ModbusProtocolParser implements ProtocolParser {
        @Override
        public Map<String, Object> parse(byte[] data) throws Exception {
            Map<String, Object> result = new HashMap<>();
            
            // 实现Modbus协议解析逻辑
            if (data.length < 8) {
                throw new IllegalArgumentException("Invalid Modbus data length");
            }
            
            // 解析Modbus帧
            int slaveId = data[0] & 0xFF;
            int functionCode = data[1] & 0xFF;
            
            result.put("slaveId", slaveId);
            result.put("functionCode", functionCode);
            
            // 根据功能码解析数据
            switch (functionCode) {
                case 0x03: // Read Holding Registers
                case 0x04: // Read Input Registers
                    int dataLength = data[2] & 0xFF;
                    byte[] registerData = new byte[dataLength];
                    System.arraycopy(data, 3, registerData, 0, dataLength);
                    result.put("data", registerData);
                    break;
                default:
                    result.put("rawData", data);
            }
            
            return result;
        }
    }
}